" ==== 核心实现 ====
let s:request_lock = 0                         " 请求锁防止并发
let s:completion_context = {}                  " 补全上下文存储
let s:response_buffer = ''                     " 原始响应缓存

" ==== 配置层 ====
let g:deepseek#enabled = 1                     " 总开关
" let g:deepseek#api_endpoint = 'https://api.deepseek.com/beta'
let g:deepseek#api_endpoint = 'https://api.deepseek.com/chat/completions'
let g:deepseek#api_key = $DEEPSEEK_API_KEY     " 必须设置环境变量
" let g:deepseek#model = 'deepseek-reasoner'    " model
let g:deepseek#model = 'deepseek-chat'    " model
let g:deepseek#max_tokens = 100                " 最大返回token数
let g:deepseek#temperature = 0.3               " 创造性控制

" 主入口：注册为omni补全
function! deepseek#Enable()
    " call deepseek#log#debug("deepseek#Enable()")
    let trigger = get(g:, "deepseek_trigger", "")
    if !empty(trigger)
        " 自定义触发快捷键
        execute "inoremap <silent> " . trigger . " <C-x><C-o>"       
    endif
    let g:deepseek = get(g:, "deepseek", {})
    let monitor_key = get(g:deepseek, "monitor_key", "")
    if !empty(monitor_key)
        call execute("nnoremap <silent> " . monitor_key . " :DeepseekMonitor<CR>")
    endif
    " 快捷键映射
    let g:deepseek_keymap = get(g:, "deepseek_keymap", { "name" : "+deepseek" })
    let g:deepseek_keymap.e = [ ":DeepseekEnable", "enable" ]
    let g:deepseek_keymap.m = [ ":DeepseekMonitor", "monitor" ]
    let g:deepseek_keymap.l = [ ":DeepseekOpenLog", "log" ]
    let g:space_keymap = get(g:, "space_keymap", { "name" : "+space" })
    let g:space_keymap.d = g:deepseek_keymap 
    " 设置补全
    set omnifunc=deepseek#Complete
endfunction

" omni补全函数 (标准接口)
function! deepseek#Complete(findstart, base)
    " call deepseek#log#debug("deepseek#Complete()")
    if a:findstart
        let l:column = deepseek#GetStartCol()
        " call deepseek#log#debug("deepseek#Complete() return " .. l:column)
        return l:column 
    else
        let s:job = deepseek#AsyncRequest(a:base)
        " call deepseek#log#debug("deepseek#Complete() get job = " .. s:job)
        return []
    endif
endfunction

" ==== 功能模块 ====
" 获取补全起始列
function! deepseek#GetStartCol()
    let s:completion_context = {
                \ 'pos': getcurpos(),
                \ 'buf': join(getline(1, line('.'))),
                \ 'filetype': &filetype
                \ }
    return col('.') - 1
endfunction

let s:cache = {}
let s:cache_ttl = 300 " 缓存有效期（秒）
let s:rate_limit = {
            \ 'remaining': 10,
            \ 'reset_time': 0,
            \ 'retry_count': 0
            \ }

" 生成缓存键（上下文哈希 + 配置参数）
function! s:CacheKey(context)
    let config_hash = sha256(printf("%d%.1f", g:deepseek#max_tokens, g:deepseek#temperature))
    return sha256(a:context . config_hash)
endfunction

" 带时效的缓存获取
function! s:GetCache(context)
    let key = s:CacheKey(a:context)
    if has_key(s:cache, key) && localtime() - s:cache[key].time < s:cache_ttl
        return s:cache[key].data
    endif
    return v:null
endfunction

" 缓存写入（自动清理过期项）
function! s:SetCache(context, data)
    let key = s:CacheKey(a:context)
    let s:cache[key] = {'time': localtime(), 'data': a:data}
    " 定期清理（每50次写入触发）
    if len(s:cache) > 50
        call filter(s:cache, 'localtime() - v:val.time < s:cache_ttl')
    endif
endfunction

function! deepseek#GetCache()
    return s:cache
endfunction

" ==== 安全验证 ====
" 上下文校验
function! deepseek#ValidateContext()
    let current_pos = getcurpos()
    return current_pos == s:completion_context.pos &&
                \ current_pos[1] == line('.') &&
                \ current_pos[2] == col('.')
endfunction

" ==== 数据处理 ====
" 格式化提示词
function! deepseek#FormatPrompt(context, filetype, base)
    let template = [
                \ 'Filetype: %s',
                \ 'Code Context:',
                \ '%s',
                \ 'Current Line: %s',
                \ 'Suggest Completion:'
                \ ]
     " 取最后20行作为上下文
     let context_line_count = get(g:, "deepseek#context_line_count", 20)
     return printf(join(template, "\n"),
                \ a:filetype,
                \ split(a:context, '\n')[-context_line_count:]->join("\n"), 
                \ a:base)
endfunction

" 构建请求负载
function! deepseek#BuildPayload(base)
    if empty(s:completion_context) | return {} | endif
    let prompt = deepseek#FormatPrompt(
                \ s:completion_context.buf,
                \ s:completion_context.filetype,
                \ a:base
                \ )
    let user_message = { 'role': 'user', 'content': prompt }
    let system_message = { 'role': 'system', 'content': 'You are an assistant.' }
    return {
                \ 'model': g:deepseek#model,
                \ 'messages': [ system_message, user_message ],
                \ 'max_tokens': g:deepseek#max_tokens,
                \ 'temperature': g:deepseek#temperature,
                \ 'stream': v:false
                \ }
endfunction

" ==== 发起异步请求 ====
function! deepseek#AsyncRequest(base)
    " call deepseek#log#debug("deepseek#AsyncRequest(" . a:base .")")
    if s:request_lock || !g:deepseek#enabled | return | endif
    " 获取完整上下文
    let context = deepseek#GetFullContext()
    " 缓存检查
    let cached = s:GetCache(context)
    if type(cached) == v:t_list && !empty(cached)
        " call deepseek#log#debug("Cache is not empty!")
        " 上下文有效性检查
        if deepseek#ValidateContext()
            call complete(col('.'), cached)
        endif
        return
    endif
    " 新增限流检查
    if s:rate_limit.remaining <= 0 && localtime() < s:rate_limit.reset_time
        echohl WarningMsg | echom "API调用已达限制，请等待".(s:rate_limit.reset_time - localtime())."秒" | echohl None
        return
    endif
    " 构建安全请求
    let payload = deepseek#BuildPayload(a:base)
    if empty(payload) | return | endif
    " 启动异步任务
    let s:request_lock = 1
    let s:response_buffer = ''
    let cmd = [
                \ 'curl', '-sS', 
                \ '-X', 'POST',
                \ '-H', 'Content-Type: application/json',
                \ '-H', 'Authorization: Bearer ' . g:deepseek#api_key,
                \ '-d', json_encode(payload),
                \ g:deepseek#api_endpoint
                \ ]
    " call deepseek#log#debug("deepseek#AsyncRequest command is " .. join(cmd, ' '))
    call job_start(cmd, {
                \ 'out_cb': function('deepseek#ResponseHandler'),
                \ 'err_cb': function('deepseek#ErrorHandler'),
                \ 'exit_cb': function('deepseek#ExitHandler'),
                \ 'mode': 'raw'
                \ })
    " 记录请求日志
    if get(g:, "deepseek_monitor_enabled", v:true)
        let request_body = {
                    \ 'headers': {'Authorization': 'Bearer ' . g:deepseek#api_key},
                    \ 'payload': payload
                    \ }
        " call deepseek#log#debug("deepseek#AsyncRequest body is " .. string(request_body))
        call deepseek#monitor#Log('REQUEST', request_body)
        " call deepseek#log#debug("deepseek#monitor#GetLogEntries() = " .. string(deepseek#monitor#GetLogEntries()))
    endif
endfunction

function! deepseek#GetFullContext()
  return join(getline(1, line('$')), "\n")[0:2000] " 限制上下文长度
endfunction

" ==== 异步回调 ====
" 响应处理
function! deepseek#ResponseHandler(channel, msg)
    " call deepseek#log#debug("deepseek#ResponseHandler(" .. a:channel .. ", ".. a:msg .. ")")
    let s:response_buffer .= a:msg
endfunction

" 错误处理
function! deepseek#ErrorHandler(channel, msg)
    " call deepseek#log#debug("deepseek#ErrorHandler(" . a:channel . ", " . a:msg . ")")
    let s:request_lock = 0
    " 解析限速头（假设API返回标准headers）
    if a:msg =~ 'Rate limit exceeded'
        let headers = s:ParseHeaders(s:response_buffer)
        let s:rate_limit.remaining = get(headers, 'x-ratelimit-remaining', 0)
        let s:rate_limit.reset_time = get(headers, 'x-ratelimit-reset', localtime()+60)
        " 指数退避重试
        let delay = float2nr(pow(2, s:rate_limit.retry_count) * 1000)
        call timer_start(delay, {-> deepseek#RetryRequest()})
        let s:rate_limit.retry_count += 1
        return
    endif
    " 其他错误处理...
    echohl ErrorMsg | echom 'API Error: ' . a:msg | echohl None
endfunction

function! s:ParseHeaders(response)
  let header_end = stridx(a:response, "\r\n\r\n")
  if header_end == -1 | return {} | endif
  let headers = split(a:response[0:header_end], "\r\n")
  let dict = {}
  for line in headers[1:] " 跳过状态行
    let colon = stridx(line, ':')
    if colon > 0
      let key = tolower(strpart(line, 0, colon))
      let dict[key] = trim(strpart(line, colon+1))
    endif
  endfor
  return dict
endfunction

function! deepseek#RetryRequest()
    " call deepseek#log#debug("deepseek#RetryRequest()")
    if s:rate_limit.remaining > 0 && localtime() > s:rate_limit.reset_time
        call deepseek#AsyncRequest(s:completion_context.base)
        let s:rate_limit.retry_count = 0
    else
        echohl WarningMsg | echom "API限速限制，请等待".(s:rate_limit.reset_time - localtime())."秒" | echohl None
    endif
endfunction

" ==== 请求完成处理 ====
function! deepseek#ExitHandler(job, status)
    " call deepseek#log#debug("deepseek#ExitHandler(" .. a:job .. ", ".. a:status .. ")")
    let s:request_lock = 0
    try
        " call deepseek#log#debug("s:response_buffer = " .. string(s:response_buffer))
        let s:response = json_decode(s:response_buffer)
        " 记录响应日志
        if get(g:, "deepseek_monitor_enabled", v:true)
            call deepseek#monitor#Log('RESPONSE', {
                        \ 'status': a:status,
                        \ 'headers': s:ParseHeaders(s:response_buffer),
                        \ 'body': s:response_buffer
                        \ })
        endif
        if has_key(s:response, 'choices')
            let s:suggestions = deepseek#FormatSuggestions(s:response.choices)
            if !empty(s:suggestions)
                " 写入缓存
                call s:SetCache(deepseek#GetFullContext(), s:suggestions)
                " 上下文有效性检查
                if deepseek#ValidateContext()
                    " 触发补全
                    call complete(col('.'), s:suggestions)
                endif
            endif
            call deepseek#ShowResponse()
        else
            call deepseek#ShowResponse()
        endif
    catch
        echohl ErrorMsg | echom 'Parse Error: ' . v:exception | echohl None
    endtry
endfunction

function! deepseek#FormatSuggestions(choices)
    " return map(a:choices, {_, v -> {'word': v.text, 'menu': '[DS]'}})
    return map(a:choices, {_, v ->  { 'word':  v.message.content, 'menu': '[DS]'}})
endfunction

function! deepseek#ShowResponse()
    echomsg "response = " .. s:response_buffer
endfunction

function! deepseek#ShowSuggestions()
    echomsg "suggestions = " .. s:suggestions
endfunction

